#include <stdio.h>
#include <string.h>
#include "datapath.h"

namespace goatgfx {

template <typename T>
DataSet<T>::DataSet(T (*create_func)(), bool (*load_func)(T, const char*), bool (*done_func)(T), void (*destr_func)(T))
{
	create = create_func;
	load = load_func;
	done = done_func;
	destroy = destr_func;

	rman = resman_create();
	resman_set_load_func(rman, dataset_load_func, this);
	resman_set_done_func(rman, dataset_done_func, this);
	resman_set_destroy_func(rman, dataset_destroy_func, this);
}

template <typename T>
DataSet<T>::~DataSet()
{
	resman_free(rman);
}

template <typename T>
void DataSet<T>::clear()
{
	resman_free(rman);
	data.clear();

	rman = resman_create();
}

template <typename T>
void DataSet<T>::update()
{
	resman_poll(rman);
}

template <typename T>
T DataSet<T>::get(const char *name) const
{
	typename std::map<std::string, T>::const_iterator iter = data.find(name);
	if(iter != data.end()) {
		return iter->second;
	}

	const char *fname, *slash;
	if((slash = strrchr(name, '/'))) {
		fname = slash + 1;
	} else {
		fname = name;
	}

	std::string path = datafile_path(fname);
	if(path.empty()) {
		fprintf(stderr, "can't find data file: %s\n", name);
		return 0;
	}

	T res = create();
	resman_lookup(rman, path.c_str(), res);
	return res;
}


// --- static functions to pass as callback to resman ---

template <typename T>
int DataSet<T>::dataset_load_func(const char *fname, int id, void *cls)
{
	DataSet<T> *dset = (DataSet<T>*)cls;
	T data = (T)resman_get_res_data(dset->rman, id);

	if(!dset->load(data, fname)) {
		return -1;
	}
	return 0;
}

template <typename T>
int DataSet<T>::dataset_done_func(int id, void *cls)
{
	DataSet<T> *dset = (DataSet<T>*)cls;

	T data = (T)resman_get_res_data(dset->rman, id);
	int load_res = resman_get_res_result(dset->rman, id);

	if(load_res != 0) {
		fprintf(stderr, "failed to load resource %d (%s)\n", id, resman_get_res_name(dset->rman, id));
	} else {
		printf("done loading resource %d (%s)\n", id, resman_get_res_name(dset->rman, id));
	}

	if(dset->done) {
		dset->done(data);
	}
	return 0;
}

template <typename T>
void DataSet<T>::dataset_destroy_func(int id, void *cls)
{
	DataSet<T> *dset = (DataSet<T>*)cls;
	T data = (T)resman_get_res_data(dset->rman, id);

	if(dset->destroy) {
		dset->destroy(data);
	}
}

}	// namespace goatgfx
